{-# LANGUAGE TypeSynonymInstances #-}

module IMatrix where

import Static
import Data.Array.IArray

newtype Matrix m n = Mat (Array (Int,Int) Double) 
        deriving (Show, Eq)
type Vector m = Matrix m (D1 DNil)
type Scalar = Matrix (D1 DNil) (D1 DNil)

scalar :: Double -> Scalar
scalar d = Mat (array ((1,1),(1,1)) [((1,1),d)])

vector :: (Cardinal m) => [Double] -> m -> Vector m
vector xs s 
    | (length xs) /= (cardToInt s)  = error "Mismatch: size is different from the length of the list"
    | otherwise                 = Mat (listArray ((1, 1),(length xs, 1)) xs)

vectorU :: [Double] -> Vector m
vectorU xs = Mat $ listArray ((1, 1), (length xs, 1)) xs

matrix :: (Cardinal m, Cardinal n) => [Double] -> m -> n -> Matrix m n
matrix xs m n
    | (length xs)   /= ((cardToInt m) * (cardToInt n)) = error "size mismatch"
    | otherwise      = Mat (listArray ((1, 1), (cardToInt m, cardToInt n)) xs)

inner :: (Cardinal m) => Vector m -> Vector m -> Scalar
inner (Mat a1) (Mat a2) 
    | bounds a1 /= bounds a2 = error "bounds must be equal"
    | otherwise = scalar $ sum $ zipWith (*) l1 l2 
        where
            l1 = elems a1
            l2 = elems a2

instance Num Scalar where
    (+) (Mat a1) (Mat a2) = scalar (a1!(1,1) + a2!(1,1))
    (-) (Mat a1) (Mat a2) = scalar (a1!(1,1) - a2!(1,1))
    (*) (Mat a1) (Mat a2) = scalar (a1!(1,1) * a2!(1,1))
    negate (Mat a) = scalar (-(a!(1,1)))
    abs (Mat a) = scalar (abs(a!(1,1)))
    signum (Mat a) = scalar (signum(a!(1,1)))
    fromInteger i = scalar (fromInteger i)
